/*Copyright (c) 2009 Michael Streif
 *
 *Permission is hereby granted, free of charge, to any person obtaining a copy
 *of this software and associated documentation files (the "Software"), to deal
 *in the Software without restriction, including without limitation the rights
 *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *copies of the Software, and to permit persons to whom the Software is
 *furnished to do so, subject to the following conditions:
 *
 *The above copyright notice and this permission notice shall be included in
 *all copies or substantial portions of the Software.
 *
 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *THE SOFTWARE.
 */


#include "keyboard.h"
#include "console.h"
#include "pic.h"
#include "asm.h"

uint8 shiftPressed = 0;
uint8 altgrPressed = 0;
uint8 escapeByte = 0;


// a value of 255 indicates that it's some shift, alt, etc.!
uint8 keymapUSlower[] = {
	'\0', '\e', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
	'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
	255,  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 255,
	'\\',  'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 255, 255, 255,
	' '};

uint8 keymapUSupper[] = {
	'\0', '\e', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
	'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
	255,  'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 255,
	'|',  'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 255, 255, 255,
	' '};

uint8 keymapDElower[] = {
	255, 255, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 225, '\'', '\b',
	'\t', 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', 129, '+', '\n',
	255,  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 148, 132, '^', 255,
	'#',  'y', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-', 255, 255, 255, ' '
	};

uint8 keymapDEupper[] = {
	255, 255, '!', '"', 255, '$', '%', '&', '/', '(', ')', '=', '?', '`', '\b',
	'\t', 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', 'O', 'P', 154, '*', '\n',
	255,  'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 153, 142, 248, 255,
	'\'',  'Y', 'X', 'C', 'V', 'B', 'N', 'M', ';', ':', '_', 255, 255, 255,
	' '};

uint8 keymapDEaltgr[] = {
	'\0', '\e', '!', 255, 255, '4', '5', '&', '{', '[', ']', '}', '\\', '\'', '\b',
	'\t', '@', 'w', 255, 'r', 't', 'z', 'u', 'i', 'o', 'p', 255, '~', '\n',
	255,  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 255, 255, '#', 255,
	'|',  'y', 'x', 'c', 'v', 'b', 'n', 255, ',', '.', '-', 255, 255, 255,
	' '};

#define SHIFTL_MAKE		0x2A
#define SHIFTR_MAKE		0x36
#define ALTGR_MAKE		0x38

#define SHIFTL_BREAK	SHIFTL_MAKE + BREAK
#define SHIFTR_BREAK	SHIFTR_MAKE + BREAK
#define ALTGR_BREAK		ALTGR_MAKE + BREAK

#define ESCAPE_uint8	0xE0
#define BREAK			0x80

#define MAX_LISTENERS	10						// max number of event reveivers

void (*eventListeners[MAX_LISTENERS]) (char, char) = {0};
int16 listenersNum = -1;

void sendKey(char key, char modifier);

void keyboardIRQ()
{
	uint8 key = inb(0x60);

	if ((key == SHIFTL_MAKE) || (key == SHIFTR_MAKE))
	{
		shiftPressed = 1;
	}

	if ((key == SHIFTL_BREAK) || (key == SHIFTR_BREAK))
	{
		shiftPressed = 0;
	}

	/*if (escapeByte == 1)
	{
		if (key == 0x48)
		{
			//up
			moveCursor(0, -1);
		}

		if (key == 0x4B)
		{
			//left
			moveCursor(-1, 0);
		}

		if (key == 0x4D)
		{
			//right
			moveCursor(1, 0);
		}

		if (key == 0x50)
		{
			//down
			moveCursor(0, 1);
		}
	}

	if (key == ESCAPE_uint8)
	{
		escapeByte = 1;
	}
	else
	{
		escapeByte = 0;
	}*/

	if ((key < 0x3A) && (keymapDElower[key] != 255))
	{
		if (shiftPressed)
		{
			sendKey(keymapDEupper[key], 0);
		}
		else
		{
			sendKey(keymapDElower[key], 0);
		}
	}

	sendEOI(1);

}

void sendKey(char key, char modifier)
{
	for (int i = 0; i < MAX_LISTENERS; i++)
	{
		if (eventListeners[i] != 0)
		{
			eventListeners[i](key, modifier);
		}
	}
}

void registerEventHandlerKbd(void (*eventFuncPtr) (char, char))
{
	if (listenersNum++ < 10)
	{
		eventListeners[listenersNum] = eventFuncPtr;
	}
}
